<?php
ArrowController::importModel("access.IArrowControlObject");
/**
 * Arrow action descriptor class
 * 
 * @version 1.0
 * @license  GNU GPL
 * @author Artur Kmera <artur.kmera@arrowplatform.org> 
 */
class ArrowBeanDescriptor implements ArrayAccess, IArrowSerializable, IArrowControlObject{

	const ACTION_BEAN = 0;
	const VIEW_HELPER_BEAN = 1;
	
	/**
	 * Handle for actions structure
	 * 
	 * @var ArrowBeanssStructure
	 */
	private $beansStructureHandle;

	/**
	 * Action id
	 *
	 * @var integer
	 */
	private $id;

	/**
	 * Action name
	 *
	 * @var string
	 */
	private $name;

	/**
	 * Action path
	 *
	 * @var string
	 */
	private $path;

	/**
	 * Action type (deliver/logic)
	 *
	 * @var string
	 */
	private $type;

	/**
	 * Action description
	 *
	 * @var string
	 */
	private $description;

	/**
	 * Parent container
	 * 
	 * @var ArrowContainer
	 */
	private $container;
	
	/**
	 * Action instance
	 * 
	 * @var Bean
	 */
	private $beanInstance = null;	

	public static function getModel() {
		return "beans.ArrowBeanDescriptor";
	}
	
	public function getUniqueId( ) {
		return array( "model" => self::getModel() , "key" => $this->getId() );
	}
	
	/**
	 * ActionDescriptor constructor
	 *
	 * @param integer $id
	 * @param string $name
	 * @param string $path
	 * @param string $type
	 * @param string $description
	 * @param boolean $auth
	 */
	public function __construct( ArrowBeansStructure $beansStructureHandle, $id, $name, $path, $type, $description ) {
		$this->beansStructureHandle = $beansStructureHandle;
		$this->id = $id;
		$this->name = $name;
		$this->path = $path;
		if( $type == "actionBean" ){
			$this->type = self::ACTION_BEAN;
		}elseif( $type == "viewHelperBean" ){
			$this->type = self::VIEW_HELPER_BEAN;
		}
		$this->description = $description;
		
		$this->container = ArrowController::getDefault()->getProject()->getContainersList()->getParentContainer($this);
	}
	
	public static function getActions(){
		return array( "execute" );
	}
	
	public function checkAccess( IArrowUser $tryier, $action ){
		$accessGroups = $tryier->getAccessGroups();
		foreach( $accessGroups as $accesGroup ){
			if( in_array($this->getKey(), $accesGroup->getBeans() ) )
				return true;
		}
		return false;
	}

	/**
	 * Saves changed action data
	 *
	 */
	public function doSave() {
		$this->beansStructureHandle->doActionDataChange( $this );
	}

	/**
	 * Returns Template Id
	 * @deprecated Use getKey
	 * @return integer
	 */
	public function getId() {
		return $this->id;
	}

	/**
	 * Returns Template Id
	 * @return integer
	 */
	public function getKEy() {
		return $this->id;
	}

	/**
	 * Returns action name
	 *
	 * @return string
	 */
	public function getName() {
		return $this->name;
	}

	/**
	 * Returns action path
	 *
	 * @return string
	 */
	public function getPath() {
		return $this->path."/".$this->getName().".php";
	}

	/**
	 * Returns mapping path /dir/sub:name
	 * 
	 * @return String
	 */
	public function getMappingPath(){
		return str_replace( $this->beansStructureHandle->sourcesDir, "", $this->path )."::".$this->getName();
	}
	
	/**
	 * Returns action type (logic/deliver)
	 *
	 * @return string
	 */
	public function getType() {
		return $this->type;
	}

	/**
	 * Returns action description
	 *
	 * @return unknown
	 */
	public function getDescription() {
		return $this->description;
	}

	/**
	 * Return action source
	 *
	 * @return string
	 */
	public function getSource() {
		
		$str =  preg_replace("/<\?php(.*)\?>/ms", "$1", file_get_contents($this->getPath()));
		$source = str_replace( "class Bean implements", "class Bean_{$this->getId()} implements", $str );
		return $source;
	}
	
	/**
	 * Returns bean instance
	 *
	 * @return Bean
	 */
	public function getBeanInstance(){

		$className = "Bean".$this->getId();
		$file = ARROW_CACHE_PATH."/beans/".str_replace( array("/", "::"), "_", $this->getMappingPath())."_".$this->getId().".php";;
		
		if( !file_exists($className) || $this->getContainer()->getForceCompile()){
			$source = file_get_contents($this->getPath());
			$source = str_replace( "class Bean implements", "class Bean{$this->getId()} implements", $source );
			file_put_contents( $file, $source );
		}
		require_once($file);
		
		if( $this->beanInstance == null )
			$this->beanInstance = new $className;
		return $this->beanInstance;
	}

	public function execute( $parameters ){
		$beanInstance = $this->getBeanInstance();
		if( $this->getType() == self::ACTION_BEAN ){
			if( !in_array( "ArrowActionBean" ,class_implements($beanInstance)))
				throw new ArrowBeansException( array( "msg" => "ActionBean don't implements ArrowActionBean interface", "id" => $this->getId(), "name" => $this->getName()) );
			return $beanInstance->perform( $parameters );
		}elseif( $this->getType() == self::VIEW_HELPER_BEAN  ){
			if( !in_array( "ArrowViewHelperBean" ,class_implements($beanInstance)))
				throw new ArrowBeansException( array( "msg" => "ViewHelperBean don't implements ArrowViewHelperBean interface", "id" => $this->getId(), "name" => $this->getName()) );
			return $beanInstance->supply( $parameters );
		}
	}
	
	/**
	 * Return bean cointainer
	 *
	 * @return ArrowContainer
	 */
	public function getContainer() {
		return $this->container;
	}

	/**
	 * Sets new action name
	 *
	 * @param string $name
	 */
	public function setName($name) {
		$this->name = $name;
	}

	/**
	 * Sets new action Path
	 *
	 * @param unknown_type $path
	 */
	public function setPath($path) {
		$this->path = $path;
	}

	/**
	 * Sets new action type
	 *
	 * @param string $type
	 * @todo Implement
	 */
	public function setType($type) {
		throw new ArrowActionsException(array (
			"msg" => "Action type change not implemented"
		));
		$this->type = $type;
	}

	/**
	 * Sets news action description
	 *
	 * @param string $description
	 */
	public function setDescription($description) {
		$this->description = $description;
	}

	/**
	 * Sets new action source
	 *
	 * @param string $source
	 */
	public function setSource($source) {
		$this->source = $source;
	}

	/**
	 * ArrayAcces implementaction
	 * 
	 * @param string $key
	 * @return boolean
	 */
	public function offsetExists($key) {
		if (isset ($this->$key))
			return true;
		return false;
	}

	/**
	 * ArrayAcces implementaction
	 * 
	 * @param string $key
	 * @return mixed
	 */
	public function offsetGet($key) {
		if ($this->offsetExists($key)) {
			return $this->$key;
		} else {
			throw new ArrowActionsException(array( "msg" => "Offset doesn't exist'", "offset" => $key ));
		}
	}
	
	/**
	 * ArrayAcces implementaction
	 * 
	 * @param string $key
	 * @param mixed value
	 */
	public function offsetSet($key, $value) {
		throw new ArrowActionsException(array( "msg" => "Can't use Array acces to set action value'" ));
	}

	/**
	 * ArrayAcces implementaction
	 * 
	 * @param string $key
	 * @return mixed
	 */
	public function offsetUnset($key) {
		throw new ArrowActionsException(array( "msg" => "Can't use Array acces to unset action value'" ));
	}
	
	/**
	 * IObjectSerialize implementaction
	 * 
	 * @return array Object in array
	 */
	 public function serialize(){
	 	$val = array();
		$val["id"] = $this->id;
		$val["name"] = $this->name;
		$val["path"] = $this->path;
		$val["type"] = $this->type;
		$val["source"] = $this->getSource();
		$val["description"] = $this->description;
		$val["auth"] = $this->auth;
	 	return $val;
	 }
	 
	 public function unserialize() {
	 	
		
	 }
	 
	 /**
	  * To string function
	  * 
	  * @return void
	  */
	 public function toString(){
	 	return (($this->type == self::ACTION_BEAN)?"Action":"ViewHelper")." bean id: '{$this->id}', path: {$this->path}, name: {$this->name}";
	 }
	
}
?>
